//
//  WeixinHelper.swift
//  MovieDemo
//  SystemConfiguration.framework,libz.dylib,libsqlite3.0.dylib,libc++.dylib
//  Created by linhan on 15-5-3.
//  Copyright (c) 2015年 linhan. All rights reserved.
//

import Foundation

struct Wechat
{
    enum ErrorCode:Int
    {
        //拒绝授权
        case Denied
        //取消授权
        case Cancel
        //授权失败
        case Fail
    }
    
    enum Gender:Int
    {
        //用户的性别，值为1时是男性，值为2时是女性，值为0时是未知
        case Unknow = 0
        case Male = 1
        case Female = 2
    }
    
    struct User
    {
        var openID:String
        var accessToken:String?
        //同一开发商名下的应用的共同ID
        var unionID:String?
        //昵称
        var screenName:String?
        //头像
        var avatarURL:String?
        //性别
        var gender:Gender = .Unknow
        //
        var city:String?
        var province:String?
        
        init(openID:String)
        {
            self.openID = openID
        }
    }
    
    struct PayData
    {
        /** 商家向财付通申请的商家id */
        var partnerId:String?
        
        /** 预支付订单 */
        var prepayId:String?
        
        /** 随机串，防重发 */
        var nonceStr:String?
        
        /** 时间戳，防重发 */
        var timeStamp:Int?
        
        /** 商家根据财付通文档填写的数据和签名 */
        var package:String?
        
        /** 商家根据微信开放平台文档对数据做的签名 */
        var sign:String?
    }
    
    struct Key
    {
        static let returnKey:String = "returnKey"
    }
    
    
}

extension NSNotification.Name
{
    public static let SWWechatPaySuccess: NSNotification.Name = NSNotification.Name(rawValue: "SWWechatPaySuccess")
    public static let SWWechatPayCancel: NSNotification.Name = NSNotification.Name(rawValue: "SWWechatPayCancel")
}

enum WechatShareScene:Int
{
    case Session
    case Space
}

protocol WeixinHelperDelegate:NSObjectProtocol
{
    func weixinSignInFail(code:Wechat.ErrorCode)
    
    func weixinSignInSuccess(openID:String, userInfo:Wechat.User?)
}

private var _manager:WeixinHelper?
class WeixinHelper: NSObject,WXApiDelegate,WebLoaderDelegate
{
    static var appID:String = ""
    static var appSecret:String = ""
    
    weak var authViewController:NSObject?
    weak var delegate:WeixinHelperDelegate?
    
    private var _user:Wechat.User?
    
    
    private var _accessToken:String?
    private var _openID:String?
    private var _unionID:String?
    
    private struct WeixinAPI
    {
        static let UserInfo:String = "UserInfo"
        static let GetAcesssToken:String = "GetAcesssToken"
        static let RefreshAcesssToken:String = "RefreshAcesssToken"
    }
    
    //微信是否安装
    class var wechatAppInstalled:Bool {
        return WXApi.isWXAppInstalled()
    }
    
    class func shared() -> WeixinHelper
    {
        _manager = _manager ?? WeixinHelper()
        return _manager!
    }
    
    class func registerApp(appID:String, appSecret:String)
    {
        WeixinHelper.appID = appID
        WeixinHelper.appSecret = appSecret
        WXApi.registerApp(appID)
    }
    
    private let webloader:WebLoader = WebLoader()
    override init() {
        super.init()
        webloader.delegate = self
    }
    
    //微信登陆授权
    func auth()
    {
        let request:SendAuthReq = SendAuthReq()
        request.scope = "snsapi_userinfo"
        //request.state = "123"
        //WXApi.sendReq(request)
        if let viewController = authViewController as? UIViewController
        {
            WXApi.sendAuthReq(request, viewController: viewController, delegate: self)
        }
    }
    
    func handleOpenURL(_ url:URL) -> Bool
    {
        return WXApi.handleOpen(url, delegate: self)
    }
    
    //发送文字内容
    func sendText(_ text:String, scene:Int = 0)
    {
        let req:SendMessageToWXReq = SendMessageToWXReq()
        req.text = text
        req.bText = true
        req.scene = Int32(scene)
        WXApi.send(req)
    }
    
    //发送图片内容
    func sendImage(_ thumb:UIImage, imageData:Data, scene:Int = 0)
    {
        let ext:WXImageObject = WXImageObject()
        ext.imageData = imageData
        let message:WXMediaMessage = WXMediaMessage()
        message.setThumbImage(thumb)
        message.mediaObject = ext
        let req:SendMessageToWXReq = SendMessageToWXReq()
        req.bText = false;
        req.message = message
        req.scene = Int32(scene)
        WXApi.send(req)
    }
    
    func sendLink(_ url:String, scene:Int = 0, title:String? = nil, desc:String? = nil)
    {
        let ext = WXWebpageObject()
        ext.webpageUrl = url
        let message:WXMediaMessage = WXMediaMessage()
        message.title = title
        message.description = desc
        message.mediaObject = ext
        let req:SendMessageToWXReq = SendMessageToWXReq()
        req.bText = false
        req.message = message
        req.scene = Int32(scene)
        WXApi.send(req)
        
    }
    
    //发起支付
    func pay(_ template:Wechat.PayData)
    {
        let req:PayReq = PayReq()
        req.partnerId = template.partnerId
        req.prepayId = template.prepayId
        req.nonceStr = template.nonceStr
        req.timeStamp = UInt32(template.timeStamp ?? 0)
        req.package = template.package
        req.sign = template.sign
        WXApi.send(req)
    }
    
    /*! @brief 发送一个sendReq后，收到微信的回应
    *
    * 收到一个来自微信的处理结果。调用一次sendReq后会收到onResp。
    * 可能收到的处理结果有SendMessageToWXResp、SendAuthResp等。
    * @param resp具体的回应内容，是自动释放的
    */
    func onResp(_ resp:BaseResp)
    {
        //trace("收到一个来自微信的处理结果:\(resp)")
        if resp is SendMessageToWXResp
        {
            let errorCode = resp.errCode
            //(errorCode: 0:成功发送 -2：取消)
            if errorCode == 0
            {
                //已成功发送
            }
            trace("发送媒体消息结果errorCode:\(errorCode)")
        }
        //登陆响应信息
        else if resp is SendAuthResp
        {
            //ERR_OK = 0(用户同意) ERR_AUTH_DENIED = -4（用户拒绝授权） ERR_USER_CANCEL = -2（用户取消）
            let errorCode = resp.errCode
            if errorCode == 0
            {
                let code:String = (resp as! SendAuthResp).code
                //let language = (resp as! SendAuthResp).lang
                //let state = (resp as! SendAuthResp).state
                //let country = (resp as! SendAuthResp).country
                getAcesssToken(code: code)
            }
            else
            {
                signInFail(errorCode == -4 ? Wechat.ErrorCode.Denied : Wechat.ErrorCode.Cancel)
            }
        }
        else if let payResp = resp as? PayResp
        {
            //openURL:wxb4ba3c02aa476ea1://pay/?returnKey=&ret=0,scheme:wxb4ba3c02aa476ea1, query:Optional("returnKey=&ret=0")
            //0 付款成功   -2 取消付款
            if payResp.errCode == 0
            {
                let returnKey:String = payResp.returnKey ?? ""
                NotificationCenter.default.post(name: NSNotification.Name.SWWechatPaySuccess, object: nil, userInfo: [Wechat.Key.returnKey:returnKey])
            }
            else
            {
                NotificationCenter.default.post(name: NSNotification.Name.SWWechatPayCancel, object: nil)
            }
        }
        
    }
    
    //授权失败
    private func signInFail(_ code:Wechat.ErrorCode)
    {
        delegate?.weixinSignInFail(code: code)
    }
    
    //授权成功
    private func signInSuccess()
    {
        if let openID = _user?.openID
        {
            delegate?.weixinSignInSuccess(openID: openID, userInfo: _user)
        }
    }
    
    private func getAcesssToken(code:String)
    {
        let url:String = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=\(WeixinHelper.appID)&secret=\(WeixinHelper.appSecret)&code=\(code)&grant_type=authorization_code"
        
        load(url: url, params: nil, method: "GET", bindArgs: ["APIName":WeixinAPI.GetAcesssToken])
    }
    
    private func parseAcesssData(data:Data)
    {
        let json = JSON(data: data)
        trace(json.description)
        if let _ = json["errcode"].int
        {
            signInFail(Wechat.ErrorCode.Fail)
        }
        else
        {
            _accessToken = json["access_token"].string
            //let expiresIn:Int? = json["expires_in"].int
            //let refreshToken:String? = json["refresh_token"].string
            //let scope:String? = json["scope"].string
            _openID = json["openid"].string
            _unionID = json["unionid"].string
            if let openID = _openID
            {
                _user = Wechat.User(openID: openID)
                _user?.unionID = _unionID
                if let accessToken = _accessToken
                {
                    _user?.accessToken = accessToken
                    getUserInfo()
                }
                else
                {
                    signInSuccess()
                }
            }
            else
            {
                signInFail(Wechat.ErrorCode.Fail)
            }
        }
    }
    
    private func refreshAcesssToken(token:String)
    {
        let url:String = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=\(WeixinHelper.appID)&grant_type=refresh_token&refresh_token=\(token)"
        load(url: url, params: nil, method: "GET", bindArgs: ["APIName":WeixinAPI.RefreshAcesssToken])
    }
    
    private func parseRefressAcesssData(data:Data)
    {
        let json = JSON(data: data)
        trace(json.description)
        if let _ = json["errcode"].int
        {
            signInFail(Wechat.ErrorCode.Fail)
        }
        else
        {
            _accessToken = json["access_token"].string
            let expiresIn:Int? = json["expires_in"].int
            let refreshToken:String? = json["refresh_token"].stringValue
            _openID = json["openid"].string
            //let scope:String? = json["scope"].stringValue
            //trace("accessToken:\(_accessToken) refreshToken:\(refreshToken) expiresIn:\(expiresIn)")
            getUserInfo()
        }
    }
    
    private func getUserInfo()
    {
        if let id = _openID,let token = _accessToken
        {
            let url:String = "https://api.weixin.qq.com/sns/userinfo?access_token=\(token)&openid=\(id)"
            load(url: url, params: nil, method: "GET", bindArgs: ["APIName":WeixinAPI.UserInfo])
        }
    }
    
    private func parseUserInfoData(data:Data)
    {
        let json = JSON(data: data)
        if let _ = json["errcode"].int
        {
            self.signInFail(Wechat.ErrorCode.Fail)
        }
        else
        {
            _user?.screenName = json["nickname"].stringValue
            _user?.avatarURL = json["headimgurl"].stringValue
            _user?.gender = Wechat.Gender(rawValue: json["sex"].intValue) ?? Wechat.Gender.Unknow
            _user?.city = json["city"].stringValue
            _user?.province = json["province"].stringValue
            signInSuccess()
        }
    }
    
    private func load(url:String, params:[String:Any]? = nil, method:String? = "GET", bindArgs:Any? = nil)
    {
        webloader.bindArgs = bindArgs
        webloader.load(url, data: params, method: method)
    }
    
    func webLoaderDidFinishLoading(_ webLoader:WebLoader, data:Data, bindArgs:Any?)
    {
        if data.length > 0
        {
            if let args = bindArgs as? [String:Any],
               let APIName = args["APIName"] as? String
            {
                if APIName == WeixinAPI.GetAcesssToken
                {
                    parseAcesssData(data: data)
                }
                else if APIName == WeixinAPI.RefreshAcesssToken
                {
                    parseRefressAcesssData(data: data)
                }
                else if APIName == WeixinAPI.UserInfo
                {
                    parseUserInfoData(data: data)
                }
            }
        }
        else
        {
            webLoaderDidFail(webLoader, error:nil, bindArgs:bindArgs)
        }
    }
    
    //接口请求失败
    func webLoaderDidFail(_ webLoader:WebLoader, error:NSError?, bindArgs:Any?)
    {
        if let args = bindArgs as? [String:Any],
           let _ = args["APIName"] as? String
        {
            signInFail(Wechat.ErrorCode.Fail)
        }
    }
    
    
    
    
    
    
}
